package edu.pku.sei.modeler.figures.anchor;

import java.util.LinkedList;
import java.util.List;

import org.eclipse.draw2d.AbstractConnectionAnchor;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PrecisionPoint;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gef.requests.ReconnectRequest;

public class SequenceDiagramAnchor extends AbstractConnectionAnchor {

	/**
	 * A relatively unique tag or name for this anchor. By "relative" we mean
	 * that it is unique within the owner figure. The tag can be used to
	 * reference an anchor within a figure even though the anchor object is
	 * deleted (and later recreated as a new object with the same tag). The
	 * model does not assume any particular "meaning" for the tag, beyond that
	 * is something unique that it can use to identify a point. The only
	 * entitity that may assign any particular meaning or structure to the tag
	 * is the Figure that create it.
	 */
	private final String tag;

	private int offSetX, offSetY;

	// A List of installed policies.
	private List<AnchorPolicy> policies;

	public SequenceDiagramAnchor(final IFigure owner, final String tag) {
		super(owner);
		this.tag = tag;
	}

	public Point getLocation(Point arg0) {
		Rectangle r = getOwner().getBounds();
		int x, y;
		y = r.y + offSetY;
		x = r.x + offSetX;
		Point p = new PrecisionPoint(x, y);
		getOwner().translateToAbsolute(p);
		return p;
	}

	public Point getReferencePoint() {
		return getLocation(null);
	}

	public void setRelativeLocation(final int x, final int y) {
		boolean moved = offSetX != x || offSetY != y;
		offSetX = x;
		offSetY = y;
		if (moved)
			fireAnchorMoved();
	}

	public int getOffsetX() {
		return offSetX;
	}

	public int getOffsetY() {
		return offSetY;
	}

	public String getTag() {
		return tag;
	}

	public void installPolicy(final AnchorPolicy policy) {
		if (policies == null)
			policies = new LinkedList<AnchorPolicy>();
		policies.add(policy);
	}

	public void removePolicy(final AnchorPolicy policy) {
		policies.remove(policy);
		if (policies.isEmpty())
			policies = null;
	}

	public boolean acceptConnectionCreate(final CreateConnectionRequest request) {
		if (policies != null) {
			for (AnchorPolicy p : policies)
				if (p.acceptConnectionCreate(this, request))
					return true;
		}
		return false;
	}

	public boolean acceptConnectionComplete(
			final CreateConnectionRequest request) {
		if (policies != null) {
			for (AnchorPolicy p : policies)
				if (p.acceptConnectionComplete(this, request))
					return true;
		}
		return false;
	}

	public boolean acceptReconnectSource(final ReconnectRequest request) {
		if (policies != null) {
			for (AnchorPolicy p : policies)
				if (p.acceptReconnectSource(this, request))
					return true;
		}
		return false;
	}

	public boolean acceptReconnectTarget(final ReconnectRequest request) {
		if (policies != null) {
			for (AnchorPolicy p : policies)
				if (p.acceptReconnectTarget(this, request))
					return true;
		}
		return false;
	}
}
